package com.andong.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.andong.domain.dto.UpdatePasswordDTO;
import com.andong.domain.entity.Coach;
import com.andong.domain.pojo.PageResult;
import com.andong.domain.pojo.Result;
import com.andong.domain.vo.StudentListVO;
import com.andong.utils.AliOSSUtils;
import com.andong.utils.AliSMSUtils;
import com.andong.utils.BaseContext;
import com.andong.utils.HmacSHA256Utils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.andong.domain.entity.Student;
import com.andong.service.StudentService;
import com.andong.mapper.StudentMapper;
import com.baomidou.mybatisplus.extension.toolkit.Db;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

import java.time.LocalDate;
import java.util.List;
import java.util.concurrent.TimeUnit;

import static com.andong.utils.SystemConstant.*;

/**
 * @author 王海云
 * @description 针对表【student】的数据库操作Service实现
 * @createDate 2023-12-30 19:26:09
 */
@Service
@Slf4j
public class StudentServiceImpl extends ServiceImpl<StudentMapper, Student>
        implements StudentService {
    @Resource
    private RedisTemplate<String, Object> redisTemplate;
    @Resource
    private StudentMapper studentMapper;
    @Resource
    private AliOSSUtils aliOSSUtils;
    @Resource
    private AliSMSUtils aliSMSUtils;

    @Override
    public Result selectById(Long id) {
        // 查询身份信息
        Student student = lambdaQuery().eq(Student::getId, id).one();
        return Result.success(student);
    }

    @Override
    public Result updatePasswordByCode(UpdatePasswordDTO dto) throws Exception {
        String phone = dto.getPhone();
        String code = dto.getCode();
        String password = HmacSHA256Utils.calculateHmacSHA256(dto.getPassword());
        Student student = getById(dto.getId());
        if (!student.getPhone().equals(phone)) {
            return Result.error(PHONE_ERROR);
        }
        // 2.从Redis获取缓存的验证码
        String realCode = (String) redisTemplate.opsForValue().get(phone);
        if (!code.equals(realCode)) {
            // 验证码错误 返回错误信息
            return Result.error(CODE_ERROR);
        }
        // 3.验证通过，修改密码
        student.setPassword(password);
        updateById(student);
        // 删除缓存的短信验证码
        redisTemplate.delete(phone);
        return Result.success();
    }

    @Override
    public Result updatePasswordByPre(UpdatePasswordDTO dto) throws Exception {
        Long id = dto.getId();
        String prePassword = HmacSHA256Utils.calculateHmacSHA256(dto.getPrePassword());
        String password = HmacSHA256Utils.calculateHmacSHA256(dto.getPassword());
        // 1.从数据库获取学员信息
        Student student = lambdaQuery().eq(Student::getId, id).one();
        // 2.判断原密码是否正确
        if (!student.getPassword().equals(prePassword)) {
            return Result.error(PRE_PASSWORD_ERROR);
        }
        // 3.更新密码
        student.setPassword(password);
        updateById(student);
        return Result.success();
    }

    @Override
    public PageResult queryList(Integer page, Integer pageSize, String name, Integer gender, Integer licenseType, Integer status, Integer learningStage, LocalDate begin, LocalDate end) {
        // 判断当前是否是教练查询
        Long id = (Long) BaseContext.getCurrentIdAndIdentity().get(CURRENT_ID);
        String identity = (String) BaseContext.getCurrentIdAndIdentity().get(CURRENT_IDENTITY);
        // 构造Student分页器
        Page<Student> studentPage = new Page<>(page, pageSize);
        // 构造Student条件查询器, 得到Student分页查询基本信息结果
        studentPage = lambdaQuery()
                .like(name != null, Student::getName, name)
                .eq(status != null, Student::getStatus, status)
                .eq(gender != null, Student::getGender, gender)
                .eq(licenseType != null, Student::getLicenseType, licenseType)
                .eq(learningStage != null, Student::getStage, learningStage)
                .eq(COACH.equals(identity), Student::getCoachId, id)
                .ge(begin != null, Student::getCreateTime, begin)
                .le(end != null, Student::getCreateTime, end)
                .orderByAsc(Student::getStage)
                .page(studentPage);
        // 使用stream流的方式对记录中的每一条数据进行处理
        List<Student> records = studentPage.getRecords();
        List<StudentListVO> voList = records.stream().map(recode -> {
            StudentListVO studentListVO = new StudentListVO();
            BeanUtil.copyProperties(recode, studentListVO);
            if (recode.getCoachId() != null) {
                Coach coach = Db.lambdaQuery(Coach.class)
                        .eq(Coach::getId, recode.getCoachId())
                        .one();
                studentListVO.setCoachName(coach.getName());
                studentListVO.setCoachUsername(coach.getUsername());
            }
            return studentListVO;
        }).toList();
        return new PageResult(studentPage.getTotal(), voList);
    }

    @Override
    public void updateImage(String url) {
        // 获取当前用户id
        Long id = (Long) BaseContext.getCurrentIdAndIdentity().get(CURRENT_ID);
        // 获取原图片URL地址
        Student student = studentMapper.selectById(id);
        String originalUrl = student.getImage();
        if (url.equals(originalUrl)) {
            // 图片相同，不执行操作
            return;
        }
        // 更新图片
        student.setImage(url);
        updateById(student);
        // 删除原图片
        if (originalUrl != null) {
            aliOSSUtils.delete(originalUrl);
        }
    }

    @Override
    public Result updatePhone(String phone, String code) {
        Long id = (Long) BaseContext.getCurrentIdAndIdentity().get(CURRENT_ID);
        // 1.校验验证码
        if (!aliSMSUtils.checkCode(phone, code)) {
            return Result.error(CODE_ERROR);
        }
        // 2.更新手机号
        lambdaUpdate()
                .eq(Student::getId, id)
                .set(Student::getPhone, phone)
                .update(getById(id));
        return Result.success();
    }

    @Override
    public Result updateStatus(Long id, Integer status) {
        // 检查参数格式
        if (!ALL_ACCOUNT_STATUS.contains(status)) {
            return Result.error(STATUS_ERROR);
        }
        lambdaUpdate()
                .eq(Student::getId, id)
                .set(Student::getStatus, status)
                .update(getById(id));
        // 更新缓存
        redisTemplate.opsForValue().set(ACCOUNT_STATUS + STUDENT + id, status, ACCOUNT_STATUS_EXPIRE, TimeUnit.MINUTES);
        return Result.success();
    }

    @Override
    public Result setCoach(Long studentId, Long coachId) {
        // 添加教练
        lambdaUpdate()
                .eq(Student::getId, studentId)
                .set(Student::getCoachId, coachId)
                .update(getById(studentId));
        return Result.success();
    }

    @Override
    public Result delete(Long id) {
        // 删除照片
        Student student = getById(id);
        if (student.getImage() != null) {
            aliOSSUtils.delete(student.getImage());
        }
        removeById(id);
        return Result.success();
    }
}




